package com.hzw.video.opengl.drawer

import android.graphics.SurfaceTexture
import android.opengl.GLES11Ext
import android.opengl.GLES20
import android.opengl.GLUtils
import com.hzw.video.opengl.IDrawer
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer

/**
 *
 * @Author:         HuaZhongWei
 * @CreateDate:     2020/9/24 9:49
 *
 * @Description:
 *
 */
class VideoDrawer : IDrawer {

    /**
     * 顶点坐标
     */
    private val vertexCoors = floatArrayOf(
        -1f, -1f,
        1f, -1f,
        -1f, 1f,
        1f, 1f
    )

    /**
     * 纹理坐标
     */
    private val textureCoors = floatArrayOf(
        0f, 1f,
        1f, 1f,
        0f, 0f,
        1f, 0f
    )

    private var program: Int = -1

    // 顶点坐标接收者
    private var vertexPosHandler: Int = -1

    // 纹理坐标接收者
    private var texturePosHandler: Int = -1

    // 纹理接收者
    private var textureHandler: Int = -1

    private var textureId: Int = -1

    private var vertexBuffer: FloatBuffer
    private var textureBuffer: FloatBuffer

    private var surfaceTexture: SurfaceTexture? = null

    init {
        vertexBuffer = ByteBuffer.allocateDirect(vertexCoors.size * 4).also {
            it.order(ByteOrder.nativeOrder())
        }.asFloatBuffer()
        vertexBuffer.put(vertexCoors)
        vertexBuffer.position(0)

        textureBuffer = ByteBuffer.allocateDirect(textureCoors.size * 4).also {
            it.order(ByteOrder.nativeOrder())
        }.asFloatBuffer()
        textureBuffer.put(textureCoors)
        textureBuffer.position(0)
    }


    override fun draw() {
        if (textureId != -1) {
            createGLProgram()
            activeTexture()
            updateTexture()
            doDraw()
        }
    }


    override fun setTextureID(id: Int) {
        textureId = id
        surfaceTexture = SurfaceTexture(id)
        surfaceTextureCallBack?.invoke(surfaceTexture!!)
    }

    private var surfaceTextureCallBack : ((SurfaceTexture) -> Unit)? = null

    override fun getSurfaceTexture(cb: (st: SurfaceTexture) -> Unit) {
        surfaceTextureCallBack = cb
    }

    override fun release() {
        GLES20.glDisableVertexAttribArray(vertexPosHandler)
        GLES20.glDisableVertexAttribArray(texturePosHandler)
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0)
        GLES20.glDeleteTextures(1, intArrayOf(textureId), 0)
        GLES20.glDeleteProgram(program)
    }

    private fun createGLProgram() {
        if (program == -1) {
            val vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, getVertexShader())
            val fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, getFragmentShader())

            program = GLES20.glCreateProgram()
            GLES20.glAttachShader(program, vertexShader)
            GLES20.glAttachShader(program, fragmentShader)
            GLES20.glLinkProgram(program)

            vertexPosHandler = GLES20.glGetAttribLocation(program, "aPosition")
            texturePosHandler = GLES20.glGetAttribLocation(program, "aCoordinate")

            textureHandler = GLES20.glGetUniformLocation(program, "uTexture")
        }
        GLES20.glUseProgram(program)
    }

    private fun getVertexShader(): String = """
        attribute vec4 aPosition;
        attribute vec2 aCoordinate;
        varying vec2 vCoordinate;
        void main() {
            gl_Position = aPosition;
            vCoordinate = aCoordinate;
        }
    """.trimIndent()

    private fun getFragmentShader(): String = """
        #extension GL_OES_EGL_image_external : require
        precision mediump float;
        varying vec2 vCoordinate;
        uniform samplerExternalOES uTexture;
        void main() {
            gl_FragColor=texture2D(uTexture, vCoordinate);
        }
    """.trimIndent()

    private fun loadShader(type: Int, sharedCode: String): Int = GLES20.glCreateShader(type).also {
        //将资源加入到着色器中，并编译
        GLES20.glShaderSource(it, sharedCode)
        GLES20.glCompileShader(it)
    }

    private fun activeTexture() {
        //激活指定纹理单元
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0)

        //绑定纹理ID到纹理单元
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureId)

        //将激活的纹理单元传递到着色器里面
        GLES20.glUniform1i(textureHandler, 0)

        //配置边缘过渡参数
        GLES20.glTexParameterf(
            GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
            GLES20.GL_TEXTURE_MIN_FILTER,
            GLES20.GL_LINEAR.toFloat()
        )
        GLES20.glTexParameterf(
            GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
            GLES20.GL_TEXTURE_MAG_FILTER,
            GLES20.GL_LINEAR.toFloat()
        )
        GLES20.glTexParameterf(
            GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
            GLES20.GL_TEXTURE_WRAP_S,
            GLES20.GL_CLAMP_TO_EDGE.toFloat()
        )
        GLES20.glTexParameterf(
            GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
            GLES20.GL_TEXTURE_WRAP_T,
            GLES20.GL_CLAMP_TO_EDGE.toFloat()
        )
    }

    private fun updateTexture() {
        surfaceTexture?.updateTexImage()
    }

    private fun doDraw() {
        //启用顶点的句柄
        GLES20.glEnableVertexAttribArray(vertexPosHandler)
        GLES20.glEnableVertexAttribArray(texturePosHandler)

        //设置着色器参数
        GLES20.glVertexAttribPointer(vertexPosHandler, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer)
        GLES20.glVertexAttribPointer(texturePosHandler, 2, GLES20.GL_FLOAT, false, 0, textureBuffer)

        //开始绘制
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4)
    }
}